//
//  REVIEWED_FOR_64BIT=YES
//
// Copyright (C) 1991, All Rights Reserved, by
// EMC Corporation, Hopkinton, Mass.
//
// This software is furnished under a license and may be used and copied
// only  in  accordance  with  the  terms  of such  license and with the
// inclusion of the above copyright notice. This software or  any  other
// copies thereof may not be provided or otherwise made available to any
// other person. No title to and ownership of  the  software  is  hereby
// transferred.
//
// The information in this software is subject to change without  notice
// and  should  not be  construed  as  a commitment by EMC Corporation.
//
// EMC assumes no responsibility for the use or  reliability  of its
// software on equipment which is not supplied by EMC.
//

//
//  RCS Log Removed.  To view log, use: rlog <file>
//

#ifndef _MEMOWNER_HXX_
#define _MEMOWNER_HXX_

#if !defined(lint) && defined(INCLUDE_ALL_RCSID)
//
// $Header: /usr/local/cvs/archive/Dart/server/src/kernel/min_kernel/include/memowner.hxx,v 11.14.12.1 2011/09/23 17:22:18 mathec Exp $
//
#endif // !lint && INCLUDE_ALL_RCSID

//
// "Owners" of memory for page-level allocation.
//
// Public definitions:
//      class Memory_Owner
//
// Private definitions:
//      class Memory_OwnerDesc
//              const Memory_OwnerMaxNameLength
//

#include <boolean.h>
#include <memdefs.h>
#include <slock.hxx>
#include <address.h>
#include <assert.h>
#include <atomic.h>		// mp_atomic_inc(), mp_atomic_dec(), atomic_t

//
// Sparse dump priorities
//
typedef enum
{
    Dump_Priority_None    = 0,  // NOT dumpped. like free list, pc device area
    Dump_Priority_Lowest  = 1,  // apps with heavy memory usage like ckpt
    Dump_Priority_Lower   = 2,  // apps with medium memory usage
    Dump_Priority_Low     = 3,  // apps with light memory usage
    Dump_Priority_Medium  = 4,  // file systems like vnode cache
    Dump_Priority_High    = 5,  // driver modules
    Dump_Priority_Higher  = 6,  // kernel components like mempool / malloc heap
    Dump_Priority_Highest = 7,  // critical/min_kernel components like frame tbl
    Dump_Priority_DumpFirst = 8 // used to dump page tables in dump compression
}
Dump_Priority;

//
// Maximum length of name kept for each registered owner.
// const int
//
enum
{
    Memory_OwnerMaxNameLength = 32
};  


//
// Non existant memory blocks (address space blocks allocated for
// PCI devices).
// Blocks are stored in the RAM in a simple list
//
class NonexistMemoryBlock
{
  public:
    addr_t                  beginBlock; // Address where block begins 
    addr_t                  endBlock;   // Address where block ends
    NonexistMemoryBlock     *nextBlock; // Ptr to the next block in the chain
    char owner[Memory_OwnerMaxNameLength]; // Owner (device driver) name.

    NonexistMemoryBlock(addr_t begin, addr_t end);

    //
    // Insert to the chain between prev and next blocks
    //
    void insert(NonexistMemoryBlock *prev, NonexistMemoryBlock *next);
  
    //
    // When non existant memory is updated, multitasking is not on yet.
    // However it has to be protected in case of multiple processors
    // will try to allocate at the same time.
    //
    static void lock();
    static void unlock();

    void dump();

  private:
    static Sthread_MutexSpl nonexistMemMutex;
};

class Memory_Frame;

//
// class Memory_OwnerDesc should be private to Memory_Owner,
// but if it were then there would be no way to initialize it.
//

class Memory_OwnerDesc
{
  private:
    friend class Memory_Owner;
    friend class DskDump;

    unsigned int    nFrames;            // number of frames owned
    Dump_Priority   priority;           // sparse dump priority
#ifdef __CDX__
    boolean_t  UseCSX;  // use csx memory, or io memory
#endif
    char label[Memory_OwnerMaxNameLength]; // human-oriented label
};


class Memory_Owner
{
    friend class DskDump;

  public:
    //
    // Owners of memory frames.
    // Note that these are small (integer) objects intended to be passed
    // by value.
    //
    // Owner values are allocated by calling registerOwner() with a string
    // label.  There is presently no way to deregister an owner, and there
    // is a fixed limit maxOwners on the number of owners.  Either of
    // these limitations might need to change in the future.
    //

    enum // const int
    {
        maxOwners = 128
    };
    //
    // Maximum number of owners that can be registered. Can't have more than
    // 254 owners as tag is unsigned char and it can store from 0 to 255 and
    // last value is reserved for notInitializedTag.
    //

    //
    // Member tag will not be intialized to 0 in this constructor, since some
    // global variable such as Dart_Image_Owner is constructed at boot time,
    // but will be initialized again in late stage by doctors.  Initializing
    // the tag in this constructor will incorrectly overwrite the tag value
    // which was set at boot time. Coverity AR 113295
    //
    Memory_Owner() {};
    //
    // This is to provide a bypass to the DIAB compiler's
    // bug where it won't allow returning const Memory_Owner
    // as const, after assigning a value to it in ::noOwner()
    // & ::freeListOwner.
    //

    Memory_Owner(const Memory_Owner& m) { tag = m.tag; };

  private:
    //
    // NOTE:  This class is used too early to have any constructors.
    //
    // A Memory_Owner is represented simply as a tag that indexes
    // into a static array of descriptors.
    //
    unsigned char tag;

    //
    // Tags for special (pre-assigned) owners:

    enum {noOwnerTag = 0, freeListOwnerTag = 1, HeapOwnerTag = 2, notInitializedTag = maxOwners+1};	// const int

    //
    // Note that the rest of this is static, not per-instance.
    //
    
    //
    // Mutex to cover updates to the per-class information.
    //
    static Sthread_MutexSpl_unconstructed mutex;

    static int nRegistered;
    //
    // invariants:
    //     0 <= tag < nRegistered
    //     2 <= nRegistered <= maxOwners
    //

    //
    // Finally, the table that contains the per-owner information.
    //
    static Memory_OwnerDesc desc[maxOwners];

  public:
    static void init(void);
    //
    // pre:  init() has not been called before
    // post: invariants are established
    //

#ifdef __CDX__
    static Memory_Owner registerOwnerSetCsx(const char *,
                         Dump_Priority pri = Dump_Priority_Lower);
#endif
    static Memory_Owner registerOwner(const char *,
        Dump_Priority pri = Dump_Priority_Lower);
    //
    // pre:  init() has been called
    // post: returns a new Memory_Owner value, or aborts if none available
    //

    static boolean_t setPriority(unsigned char tag, int priority);
    //
    // update dump priority for a given memory owner tag
    //

    static boolean_t getTagByLabel(const char *label, unsigned char &tag);
    //
    // get the memory owner tag for a given name/label
    //

    static boolean_t getTagByLabelLocked(const char *label, unsigned char &tag);
    //
    // get the memory owner tag for a given name/label with mutex held by caller
    //

    static char *getLabelByTag(unsigned char tag);

    int getUsedSpace();

#ifdef __CDX__
    boolean_t UseCSX() const;
    void SetCSX(void) const;
#endif
    //
    // get the frames occupied by this owner
    //

    void addFrame(void) const;
    //
    // update per-owner information when a frame is assigned
    //
    
    void deleteFrame(void) const;
    //
    // update per-owner information when a frame is de-assigned
    //

    boolean_t operator==(const Memory_Owner &m) const;
    //
    // post: returns FALSE if this and m are not equal
    //

    boolean_t operator!=(const Memory_Owner &m) const;
    //
    // post: returns FALSE if this and m are equal
    //

  public:
    //
    // Memory_Owner constants, implemented as functions so that no
    // static constructors are required
    //

    static const Memory_Owner notInitializedOwner();

    static const Memory_Owner noOwner();
    //
    // pre:  init() has been called
    // post: returns the owner used for any unassigned frames
    //

    static const Memory_Owner freeListOwner();
    //
    // pre:  init() has been called
    // post: returns the owner used for the free list
    //

    static const Memory_Owner HeapOwner();
    // pre:  init() has been called
    // post: returns the owner used for the heap malloc

#ifdef Memory_DEBUG
    //
    // debugging and testing support
    //
  private:
    static int initCalled;
#endif // Memory_DEBUG

  public:
    static void dump();
    //
    // Print information about all owners.
    //

    //
    // Print information about non existing memory owners.
    //
    static void dumpNonexistMemoryBlocks();

    //
    // functions to convert to/from integer representation of values
    //
    int tagValue() const { return tag; }
    //
    // post: returns values as an integer
    //

#ifdef Memory_DEBUG
    //
    // debugging and testing support
    //
    void setTag(int tagValue) { tag = tagValue; }
#endif // Memory_DEBUG

    boolean_t assignValue(int n);
    //
    // post: this Memory_Owner takes on the tag value n if it is a valid
    //       owner; returns FALSE if n is not a currently registered tag value
    //

    static uint64_t GetFreelistMemory(void);

public:
    //
    // List of PCI memory space ownerss.
    //
    static NonexistMemoryBlock *nonexistMemoryBlocksPtr;

};


//
// In-line implementations for class Memory_Owner
//

#ifdef __CDX__
inline boolean_t
Memory_Owner::UseCSX(void) const
{
   return desc[tag].UseCSX;
}
inline void
Memory_Owner::SetCSX(void) const
{
   desc[tag].UseCSX=TRUE;
}
#endif
//
// Memory_Owner::addFrame()
//
inline void
Memory_Owner::addFrame(void) const
{
    Memory_ASSERT(tag <= nRegistered);
    mp_atomic_inc((volatile atomic_t *)&(desc[tag].nFrames));
}


//
// Memory_Owner::deleteFrame()
//
inline void
Memory_Owner::deleteFrame(void) const
{
    Memory_ASSERT(tag <= nRegistered);
    mp_atomic_dec((volatile atomic_t *)&(desc[tag].nFrames));
}


//
// Memory_Owner::operator==()
//
inline boolean_t
Memory_Owner::operator==(const Memory_Owner &m) const
{
    return tag == m.tag;
}


//
// Memory_Owner::operator!=()
//
inline boolean_t
Memory_Owner::operator!=(const Memory_Owner &m) const
{
    return tag != m.tag;
}


//
// Memory_Owner::getUsedSpace()
//
inline int
Memory_Owner::getUsedSpace()
{
    Memory_ASSERT(tag <= nRegistered);
    return desc[tag].nFrames;
}


//
// The next 2 routines work because Memory_Owner is small enough
// to fit into an integer, so the compiler doesn't even call
// the constructor. Change the size of Memory_Owner and all
// will collapse.
//


//
// Memory_Owner::noOwner()
//
inline const Memory_Owner
Memory_Owner::noOwner()
{
    Memory_Owner dummy;
    dummy.tag = noOwnerTag;
    return dummy;
}


//
// Memory_Owner::freeListOwner()
//
inline const Memory_Owner
Memory_Owner::freeListOwner()
{
    Memory_Owner dummy;
    dummy.tag = freeListOwnerTag;
    return dummy;
}

inline const Memory_Owner Memory_Owner::HeapOwner()
{
    Memory_Owner dummy;
    dummy.tag = HeapOwnerTag;
    return dummy;
}

inline const Memory_Owner Memory_Owner::notInitializedOwner()
{
    Memory_Owner dummy;
    dummy.tag = notInitializedTag;
    return dummy;
}


typedef void memCntPrintFn();
typedef ulong32 memCountFn();

class memoryCounter
{
  public:
    static void         printAll(boolean_t, boolean_t);
    static void         resetAll();
    static uint64_t     getTotal(void *);

  private:
    memoryCounter           *next;
    memCntPrintFn           *printFn;
    memCountFn              *countFn;
    static memoryCounter    *head;

  public:
    memoryCounter (memCntPrintFn *p, memCountFn *f);
};

#ifdef __CDX__
// value below is in 8k frames, signifies a large dart I/O memory allocation.
#define MEMORY_OWNER_LARGE_DART_BUCKET 100000
#endif

#endif // !_MEMOWNER_HXX_
